package com.depth.viewer.manager
{
	import com.depth.viewer.container.IWidgetContainer;
	import com.depth.viewer.container.ViewerContainer;
	import com.depth.viewer.container.definition.IWidgetContainerDefinition;
	import com.depth.viewer.events.AppEvent;
	import com.depth.viewer.facade.IWidgetFacade;
	import com.depth.viewer.facade.IocAppFacade;
	import com.depth.viewer.facade.WidgetFacade;
	import com.depth.viewer.loader.IWidgetLoader;
	import com.depth.viewer.utils.Util;
	import com.depth.viewer.widget.BaseWidget;
	import com.depth.viewer.widget.BaseWidgetMediator;
	import com.depth.viewer.widget.IBaseMediatorWidget;
	import com.depth.viewer.widget.IBaseWidget;
	import com.depth.viewer.widget.IFocusWidget;
	import com.depth.viewer.widget.IWidget;
	import com.depth.viewer.widget.WidgetStates;
	import com.depth.viewer.widget.definition.IBaseWidgetDefinition;
	import com.depth.viewer.widget.definition.IWidgetDefinition;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.utils.getDefinitionByName;
	
	import mx.core.FlexGlobals;
	import mx.core.IFlexDisplayObject;
	import mx.managers.PopUpManager;
	import mx.managers.PopUpManagerChildList;
	
	import org.puremvc.as3.interfaces.IMediator;
	import org.puremvc.as3.interfaces.INotification;
	import org.puremvc.as3.interfaces.IProxy;
	import org.puremvc.as3.patterns.facade.Facade;
	import org.puremvc.as3.patterns.mediator.Mediator;
	import org.springextensions.actionscript.context.support.XMLApplicationContext;
	import org.springextensions.actionscript.puremvc.patterns.facade.IocFacade;
	
	public class WidgetManager extends Mediator implements IWidgetManager,IWidgetDisplayManager
	{
		private var _registry:IWidgetContainerRegistry;
		private var _loader:IWidgetLoader;
		private var _loadingList:Array = [];
		private var _unLoadingList:Array = [];
		private var _loading:Boolean = false;
		public function WidgetManager(registory:IWidgetContainerRegistry,loader:IWidgetLoader)
		{
			this._registry = registory;
			this._loader = loader;
			this._loader.loadedHandler = widgetLoadedHandler;
			this._loader.loadFailHandler = widgetLoadFailHandler;
			this._loader.unloadedHandler = unloadedHandler;
			
			super("WidgetManager");
		}
		
		
		override public function listNotificationInterests():Array{
			return [IocAppFacade.SET_WIDGET_STATE,IocAppFacade.LOAD_WIDGET,IocAppFacade.REMOVE_WIDGET,IocAppFacade.UNLOAD_WIDGET,IocAppFacade.CONFIG_LOADED,IocAppFacade.WIDGET_CONFIG_LOADED];
		}
		override public function handleNotification(notification:INotification):void{
			switch(notification.getName()){
				case IocAppFacade.SET_WIDGET_STATE:
					var widgetId:String = notification.getBody()[0] as String;
					var state:String = notification.getBody()[1]  as String;
					
					var widget:IBaseWidget = ViewerSystemManager.getInstance().widgetManager.getRegistry().getRegistry().getRegistedWidget(widgetId);
					if(widget){
						widget.setState(state);
					}
					break;
				case IocAppFacade.LOAD_WIDGET:
					var param:Object = notification.getBody();
					var display:Boolean = true;
					var title:String;
					var id:String;
					var runingParams:Object;
					if(param is String){
						id = param as String;
					}else{
						id = param.id;
						display = param.display == undefined?true:param.display;
						title = param.title;
						
						runingParams = param.runingParams;
					}
					try{
						ViewerContainer.dispatchEvent(new AppEvent(IocAppFacade.LOAD_WIDGET,id));
						loadWidget(id,display,title,runingParams);
					}catch(err:Error){
						trace(err.message);
						trace(err.getStackTrace());
					}
					break; 
				case IocAppFacade.REMOVE_WIDGET:
					var param:Object = notification.getBody();
					var id:String;
					if(!param) return;
					if(param is String){
						id = param as String;
					}else{
						id = param.id;
					}
					try{
						removeWidget(id);
					}catch(err:Error){
						trace(err.message);
						trace(err.getStackTrace());
					}
					break;
				case IocAppFacade.UNLOAD_WIDGET:
					var param:Object = notification.getBody();
					var id:String;
					if(param is String){
						id = param as String;
					}else{
						id = param.id;
					}
					try{
						unLoadWidget(id);
					}catch(err:Error){
						trace(err.message);
						trace(err.getStackTrace());
					}
					
					break;
				case IocAppFacade.CONFIG_LOADED:
					break;
				case IocAppFacade.WIDGET_CONFIG_LOADED:
					try{
						var widget:IBaseWidget = notification.getBody().widget;
						var context:XMLApplicationContext = notification.getBody().context;
						var wFacade:IWidgetFacade = notification.getBody().facade as IWidgetFacade;
						
						if(context && wFacade){
							registerWidgetProxys(context,wFacade);
							registerWidgetCommands(context,wFacade);
							registerWidgetMediators(context,widget,wFacade);
							registerBeans(widget);
						}
						
						sendNotification(IocAppFacade.WIDGET_LOADED,widget);
						ViewerContainer.dispatchEvent(new AppEvent(IocAppFacade.WIDGET_LOADED,widget));
					}catch(err:Error){
						trace(err.getStackTrace());
					}
					_loading = false;
					loadNextWidget();
					break;
			}
		}
		
		public function getRegistry():IWidgetContainerRegistry
		{
			return this._registry;
		}
		public function getLoader():IWidgetLoader{
			return this._loader;
		}
		public function loadWidget(id:String,display:Boolean = true,title:String = null,runingParams:Object = null):void
		{
			var def:IWidgetDefinition = getRegistry().getRegistedWidgetDefinition(id);
			if(!def){
				def = getRegistry().getRegistry().getRegistedWidgetDefinition(id);
			}
			
			if(def){
				if(def is IBaseWidgetDefinition){
					IBaseWidgetDefinition(def).display = display;
					if(title)
						IBaseWidgetDefinition(def).label = title;
					if(runingParams)
						IBaseWidgetDefinition(def).runingParams = runingParams;
					
					var importDefs:Array = getImportWidgetDefs(def as IBaseWidgetDefinition);
					
					Util.connect(_loadingList,importDefs);
				}
				_loadingList.push(def);
				loadNextWidget();
			}else{
				throw new Error("要加载的模块定义未注册,请检查配置文件！" + id);
			}
		}
		private function getImportWidgetDefs(def:IBaseWidgetDefinition,defs:Array = null):Array{
			if(!defs){
				defs = [];
			}
			var importWidgets:Array = def.importWidgets;
			if(importWidgets && importWidgets.length > 0){
				for each(var wName:String in importWidgets){
					var df:IBaseWidgetDefinition = getRegistry().getRegistry().getRegistedWidgetDefinition(wName) as IBaseWidgetDefinition;
					if(df){
						if(Util.indexOf(defs,df) == -1){
							defs.unshift(df);
							getImportWidgetDefs(df,defs);
						}
					}
				}
			}
			
			return defs;
		}
		
		private function getExportWidgets(def:IBaseWidgetDefinition):Array{
			var defs:Array = [];
			
			var widgetDefs:Array = getRegistry().getRegistry().getRegistedWidgetDefinitions();
			for each(var wdef:IBaseWidgetDefinition in widgetDefs){
				var wImportWidgets:Array = wdef.importWidgets;
				if(Util.indexOf(wImportWidgets,def.id) != -1){
					defs.push(wdef.id);
				}
			}
			return defs;
		}
		public function removeWidget(id:String):void
		{
			var widget:IBaseWidget = getRegistry().getRegistry().getRegistedWidget(id);
			if(!widget){
				trace("不能删除未加载的模块!" + id);
				return;
			}
			try{			
				widget.stop();
			}catch(err:Error){
				trace("------------------ widget Id is " +id);
				trace(err.getStackTrace());
			}
			removeWidgetDsiplay(widget);
			if(widget.definition is IBaseWidgetDefinition){
				IBaseWidgetDefinition(widget.definition).widgetState = WidgetStates.WIDGET_CLOSED;
			}
			sendNotification(IocAppFacade.WIDGET_REMOVED,widget);
			ViewerContainer.dispatchEvent(new AppEvent(IocAppFacade.WIDGET_REMOVED,widget));
		}
		public function unLoadWidget(id:String):void{
			var def:IWidgetDefinition = getRegistry().getRegistry().getRegistedWidgetDefinition(id);
			if(def is IBaseWidgetDefinition && IBaseWidgetDefinition(def).isBaseWidget){
				trace("不能卸载基础模块" + id);
				//throw new Error("不能卸载基础模块! " + id);
			}
			_unLoadingList.push(def);
			unLoadNextWidget();
		}
		private function unLoadWidgetById(id:String):void
		{
			var def:IWidgetDefinition = getRegistry().getRegistry().getRegistedWidgetDefinition(id);
			var widget:IBaseWidget = getRegistry().getRegistry().getRegistedWidget(id);
			if(!widget){
				if(!widget){
					throw new Error("不能卸载未加载的模块!" + id);
				}
			}
			try{
				widget.stop();
				widget.destroy();
			}catch(err:Error){
				trace(err.getStackTrace());
			}
			try{
				_loading = true;
				_loader.unload(def);
			}catch(err:Error){
				_loading = false;
				unLoadNextWidget();
				trace(err.message);
				trace(err.getStackTrace());
			}finally{
				if(def is IBaseWidgetDefinition && def.context){
					unloadContext(def as IBaseWidgetDefinition);
				}
			}
			removeWidgetDsiplay(widget);
			getRegistry().getRegistry().unRegisterWidget(def.id);
			
			if(def is IBaseWidgetDefinition)
				IBaseWidgetDefinition(def).widgetState = WidgetStates.WIDGET_UNLOADED;
			
			trace("己卸载 Widget:  " + id);
			
			sendNotification(IocAppFacade.WIDGET_UNLOADED,widget);
			ViewerContainer.dispatchEvent(new AppEvent(IocAppFacade.WIDGET_UNLOADED,widget));
			
			_loading = false;
			unLoadNextWidget();
		}
		private function unLoadNextWidget():void{
			if(_loading){
				return;
			}
			if(_unLoadingList.length > 0){
				var def:IWidgetDefinition = _unLoadingList.shift();
				if(def){
					try{
						unLoadWidgetById(def.id);
					}catch(err:Error){
						trace(err.getStackTrace());
						_loading = false;
						unLoadNextWidget();
					}
				}
			}
		}
		
		private function loadWidgetByDefinition(def:IWidgetDefinition):void{
			var widget:IWidget = getRegistry().getRegistedWidget(def.id);
			if(!widget){
				widget = getRegistry().getRegistry().getRegistedWidget(def.id);
			}
			trace("-------------------------------------------------------------------开始加载Widget : " + def.id);
			if(widget){
				if(def is IBaseWidgetDefinition){
					configWidget(def as IBaseWidgetDefinition,widget as IBaseWidget);
				}else if(def is IWidgetContainerDefinition){
					configWidgetContainer(def as IWidgetContainerDefinition,widget as IBaseWidget);
				}
				loadNextWidget();
				return;
			}
			_loading = true;
			getLoader().load(def,FlexGlobals.topLevelApplication.moduleFactory);
		}
		private function loadNextWidget():void{
			if(_loading){
				return;
			}
			if(_loadingList.length > 0){
				var def:IWidgetDefinition = _loadingList.shift();
				try{
					loadWidgetByDefinition(def);
				}catch(err:Error){
					trace(err.getStackTrace());
					_loading = false;
					loadNextWidget();
				}
			}
		}
		
		private function widgetLoadedHandler(def:IWidgetDefinition,widget:IBaseWidget):void{
			//_loading = false;
			
			if(def is IBaseWidgetDefinition){
				configWidget(def as IBaseWidgetDefinition,widget);
			}else if(def is IWidgetContainerDefinition){
				configWidgetContainer(def as IWidgetContainerDefinition,widget);
			}
			
			//loadNextWidget();
		}
		private function unloadedHandler(def:IWidgetDefinition):void{		
			_loading = false;
			unLoadNextWidget();
		}
		
		private function widgetLoadFailHandler(errMsg:String):void{
			trace(errMsg);
			_loading = false;
			loadNextWidget();
		}
		private function configWidget(def:IBaseWidgetDefinition,widget:IBaseWidget):void{
			try{
				
				widget.definition = def;
				
				var wgtContainerDef:IWidgetContainerDefinition = def.container;
				var wgtContainer:IWidgetContainer = null;
				if(wgtContainerDef)
					wgtContainer = getRegistry().getRegistedWidget(wgtContainerDef.id) as IWidgetContainer;
				
				
				var config:String = def.config;
				var xmlContext:XMLApplicationContext = def.context;
				var wFacade:IWidgetFacade = def.facade as IWidgetFacade;
				if(!wFacade){
					Facade.removeCore(def.id);
					wFacade = new WidgetFacade(def.id);
					
					if(widget is IBaseMediatorWidget){
						var mediator:Mediator = new BaseWidgetMediator(widget.widgetId,widget,IBaseMediatorWidget(widget).listNotificationInterests,IBaseMediatorWidget(widget).handleNotification); 
						wFacade.registerMediator(mediator)
						IocAppFacade.getInstance().registerMediator(mediator);
					}
				}
				getRegistry().getRegistry().registerWidget(widget);
				if(config && config.length > 0 && !xmlContext){
					xmlContext = wFacade.container as XMLApplicationContext;
					def.context = xmlContext;
					xmlContext.parent = IocAppFacade.getInstance().container;
					
					xmlContext.addEventListener(Event.COMPLETE,function(event:Event):void{
						
						sendNotification(IocAppFacade.WIDGET_CONFIG_LOADED,{widget:widget,context:xmlContext,facade:wFacade});
						if(def.display && wgtContainer){
							addWidgetDisplay(widget,wgtContainer,def.popupMode,def.modalPopup,def.centerPopupMode);
						}
						
						
						wFacade.widget = widget;
						def.facade = wFacade as IocFacade;
						try{
							widget.run(def.runingParams);
						}catch(err:Error){
							trace(err.getStackTrace());
						}
						def.runingParams = null;//参数只能在调用加载widget的时候使用
					});
					
					wFacade.initializeIocContainer(config);
				}else{
					if(xmlContext)
						sendNotification(IocAppFacade.WIDGET_CONFIG_LOADED,{widget:widget,context:xmlContext,facade:wFacade});
					else
						sendNotification(IocAppFacade.WIDGET_CONFIG_LOADED,{widget:widget,context:null,facade:null});
					
					if(def.display && wgtContainer){
						addWidgetDisplay(widget,wgtContainer,def.popupMode,def.modalPopup,def.centerPopupMode,def.facade  == null);
					}
					
					wFacade.widget = widget;
					def.facade = wFacade as IocFacade;
					try{
						widget.run(def.runingParams);
					}catch(err:Error){
						trace(err.getStackTrace());
					}
				}
				def.widgetState = WidgetStates.WIDGET_LOADED;
				trace("-------------------------------------------------------------------己加载Widget : " + def.id);
			}catch(err:Error){
				trace(err.message);
				trace(err.getStackTrace());
				_loading = false;
				loadNextWidget();
			}/*finally{
			}*/
		}
		
		
		public function focusInWidget(widget:IFocusWidget):void{
			widget.focusIn();
		}
		public function focusOutWidget(widget:IFocusWidget):void{
			widget.focusOut()
		}
		
		
		public function addWidgetDisplay(widget:IBaseWidget,wgtContainer:IWidgetContainer,popupMode:Boolean = false,modalPopup:Boolean = false,centerPopupMode:Boolean = false,resetPosition:Boolean = true):void{
			if(!popupMode){
				var index:int = -1;
				if(widget.definition is IBaseWidgetDefinition && IBaseWidgetDefinition(widget.definition).isBaseWidget)
					index = 0;
				wgtContainer.addWidget(widget,index);
			}else{
				widget.container = wgtContainer;
				widget.isDragDropable = true;
				widget.isDraggable = true;
				widget.isResizeable  = true;
				PopUpManager.addPopUp(widget as IFlexDisplayObject,wgtContainer as DisplayObject,modalPopup,PopUpManagerChildList.PARENT,FlexGlobals.topLevelApplication.moduleFactory);
				if(centerPopupMode){
					PopUpManager.centerPopUp(widget as IFlexDisplayObject);
				}
			}
			widget.map = IocAppFacade.getInstance().map;
			
			widget.setState(WidgetStates.WIDGET_OPENED);
			
			if(resetPosition){
				var def:IBaseWidgetDefinition = widget.definition as IBaseWidgetDefinition;
				var wx:Number = Number(def.x);
				var wy:Number = Number(def.y);
				var wz:Number = Number(def.z);
				var wleft:Object = def.left;
				var wtop:Object = def.top;
				var wright:Object = def.right;
				var wbottom:Object = def.bottom;
				widget.setRelativePosition(wleft, wright, wtop, wbottom);
				if(wx || wy)
					widget.setXYPosition(wx, wy);
				if(wz != -1)
					widget.setXYPosition(wx,wy,wz);
			}
			
			if(widget is IFocusWidget)
				focusInWidget(widget as IFocusWidget);  //当前加载的widget为当前操作组件
		}
		public function removeWidgetDsiplay(widget:IBaseWidget):void{
			try{
				var def:IBaseWidgetDefinition = widget.definition as IBaseWidgetDefinition;
				if(!def.popupMode){
					var container:IWidgetContainer = widget.container;
					if(container){
						container.removeWidget(widget.widgetId);
					}
				}else{
					PopUpManager.removePopUp(widget as IFlexDisplayObject);
				}
			}catch(e:Error){
				trace(e.name);
			}
		}
		private function configWidgetContainer(def:IWidgetContainerDefinition,widget:IBaseWidget):void
		{
			
			var container:IWidgetContainer = widget as IWidgetContainer;
			if(!container){
				return ;
			}
			getRegistry().registerWidget(container as IBaseWidget);			
			
			//var ctnIVE:IVisualElement = bcontainer as IVisualElement;
			component.addWidget(container as IBaseWidget);
			
			sendNotification(IocAppFacade.WIDGET_CONFIG_LOADED,{widget:widget,context:null});
		}
		
		
		private function registerBeans(widget:IBaseWidget):void{
			var def:IBaseWidgetDefinition = widget.definition as IBaseWidgetDefinition;
			var beanKeys:Array = Util.getObjectAttributes(def.beanNames);
			var context:IocAppFacade = IocAppFacade.getInstance();
			for each(var key:String in beanKeys){
				var beanName:String = def.beanNames[key];
				var bean:Object = context.getObject(beanName);
				widget[key] = bean;
			}
		}
		private function registerWidgetMediators(context:XMLApplicationContext,widget:IBaseWidget,wFacade:IWidgetFacade):void{
			var mediatorNames:Array = context.getObjectNamesForType(IMediator);
			for each(var mediatorName:String in mediatorNames){
				var mediator:IMediator = context.getObject(mediatorName) as IMediator;
				mediator.setViewComponent(widget);
				IocAppFacade.getInstance().registerMediator(mediator);
				wFacade.registerMediator(mediator);
			}
		}
		private function registerWidgetProxys(context:XMLApplicationContext,wFacade:IWidgetFacade):void{
			var proxyNames:Array = context.getObjectNamesForType(IProxy);
			for each(var proxyName:String in proxyNames){
				var proxy:IProxy = context.getObject(proxyName) as IProxy;
				IocAppFacade.getInstance().registerProxy(proxy);
				wFacade.registerProxy(proxy);
			}
		}
		private function registerWidgetCommands(context:XMLApplicationContext,wFacade:IWidgetFacade):void{
			if(context){
				//var featureLayer:Class = context.getClassForName("FeatureLayer");
			}
		}
		
		
		private function unRegisterWidgetMediators(context:XMLApplicationContext,wFacade:IWidgetFacade):void{
			var mediatorNames:Array = context.getObjectNamesForType(IMediator);
			for each(var mediatorName:String in mediatorNames){
				IocAppFacade.getInstance().removeMediator(mediatorName);
				wFacade.removeMediator(mediatorName);
				context.removeObjectDefinition(mediatorName);
			}
		}
		private function unRegisterWidgetProxys(context:XMLApplicationContext,wFacade:IWidgetFacade):void{
			var proxyNames:Array = context.getObjectNamesForType(IProxy);
			for each(var proxyName:String in proxyNames){
				IocAppFacade.getInstance().removeProxy(proxyName);
				wFacade.removeProxy(proxyName);
				context.removeObjectDefinition(proxyName);
			}
		}
		private function unRegisterWidgetCommands(context:XMLApplicationContext,wFacade:IWidgetFacade):void{
			if(context){
				//var featureLayer:Class = context.getClassForName("FeatureLayer");
			}
		}
		private function unloadContext(def:IBaseWidgetDefinition):void{
			unRegisterWidgetMediators(def.context,def.facade as IWidgetFacade);
			unRegisterWidgetCommands(def.context,def.facade as IWidgetFacade);
			unRegisterWidgetProxys(def.context,def.facade as IWidgetFacade);
			Facade.removeCore(def.id);
			def.context = null;
			def.facade = null;
		}
		public static function showAllWidget():void{
			var widgets:Array = ViewerSystemManager.getInstance().widgetManager.getRegistry().getRegistry().getRegistedWidgets();
			for each(var widget:BaseWidget in widgets){
				if(!IBaseWidgetDefinition(widget.definition).isBaseWidget)
					widget.visible = true;
			}
		}
		public static function hideAllWidget():void{
			var widgets:Array = ViewerSystemManager.getInstance().widgetManager.getRegistry().getRegistry().getRegistedWidgets();
			for each(var widget:BaseWidget in widgets){
				if(!IBaseWidgetDefinition(widget.definition).isBaseWidget)
					widget.visible = false;
			}
		}
		public static function removeAllWidget():void{
			var widgets:Array = ViewerSystemManager.getInstance().widgetManager.getRegistry().getRegistry().getRegistedWidgets();
			for each(var widget:IBaseWidget in widgets){
				if(!IBaseWidgetDefinition(widget.definition).isBaseWidget)
					IocAppFacade.sendNotification(IocAppFacade.REMOVE_WIDGET,widget.widgetId);
			}
		}
		public static function unloadAllWidget():void{
			var widgets:Array = ViewerSystemManager.getInstance().widgetManager.getRegistry().getRegistry().getRegistedWidgets();
			for each(var widget:IBaseWidget in widgets){
				if(!IBaseWidgetDefinition(widget.definition).isBaseWidget)
					IocAppFacade.sendNotification(IocAppFacade.UNLOAD_WIDGET,widget.widgetId);
			}
		}
		private function get component():IWidgetContainer{
			return super.viewComponent as IWidgetContainer;
		}
	}
}